# -*- coding: utf-8 -*-
"""
网络扫描统一管理器模块
负责处理网络扫描相关的所有逻辑，包括UI交互和业务处理
"""

from PySide2.QtWidgets import QComboBox, QMessageBox
from PySide2.QtCore import QObject, Signal
from gglobal import logger, config
from ..threadcore.scan_car_thread import NetworkScanner
from ..handlercore.ipvalidator import IPValidator, NetworkValidator, IPValidationHelper
from ..handlercore.language_manager import LanguageManager
from ..handlercore.connection_manager import ScanStateManager


class NetworkScanManager(QObject):
    """网络扫描统一管理器类
    
    整合了网络扫描的UI管理和业务逻辑处理功能
    """
    
    # 定义信号
    device_found = Signal(str, str)  # IP地址, 设备名称
    scan_finished = Signal()  # 扫描完成
    local_networks_updated = Signal(list)  # 本地网段更新
    # scan_status_changed = Signal(bool)  # 扫描状态变化
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent_widget = parent
        
        # 初始化组件
        self.language_manager = LanguageManager()
        
        # UI组件引用（由主界面传入）
        self.network_combo = None
        self.ip_combo = None
        self.scan_button = None
        self.local_network_button = None
        
        # 业务逻辑组件
        self.network_scanner = None
        self._scan_state_manager = ScanStateManager(self)
        # self._scan_state_manager.scan_status_changed.connect(self.scan_status_changed)
        self._scan_state_manager.scan_status_changed.connect(self._on_scan_status_changed)
        
        logger.info("网络扫描统一管理器初始化完成")
        
    def set_ui_components(self, network_combo, ip_combo, scan_button, local_network_button):
        """设置UI组件引用"""
        self.network_combo = network_combo
        self.ip_combo = ip_combo
        self.scan_button = scan_button
        self.local_network_button = local_network_button
        
        # 设置输入校验
        self.setup_ip_validation()
        self.setup_network_validation()
        
        # 连接按钮信号
        self.scan_button.clicked.connect(self.on_scan_clicked)
        self.local_network_button.clicked.connect(self.on_get_local_network_clicked)
        
    def setup_ip_validation(self):
        """设置IP输入校验"""
        if not self.ip_combo:
            return
            
        # 获取可编辑的LineEdit组件
        line_edit = self.ip_combo.lineEdit()
        if line_edit:
            # 设置IP验证器
            ip_validator = IPValidator(self.parent_widget)
            line_edit.setValidator(ip_validator)
            # 连接文本改变信号进行实时校验
            line_edit.textChanged.connect(self.validate_ip_input)
            
    def setup_network_validation(self):
        """设置网段输入校验"""
        if not self.network_combo:
            return
            
        # 获取可编辑的LineEdit组件
        line_edit = self.network_combo.lineEdit()
        if line_edit:
            # 设置网段验证器
            network_validator = NetworkValidator(self.parent_widget)
            line_edit.setValidator(network_validator)
            # 连接文本改变信号进行实时校验
            line_edit.textChanged.connect(self.validate_network_input)
            
    def validate_ip_input(self, text):
        """实时校验IP输入"""
        # 检查是否包含中文字符
        if IPValidationHelper.contains_chinese(text):
            cleaned_text = IPValidationHelper.clean_chinese_chars(text)
            line_edit = self.ip_combo.lineEdit()
            if line_edit:
                # 阻止信号递归
                line_edit.blockSignals(True)
                line_edit.setText(cleaned_text)
                line_edit.blockSignals(False)
                return {'valid': False, 'cleaned_text': cleaned_text, 'error': '输入包含非法字符'}
        
        # 如果包含设备名称，提取IP部分
        extracted_ip = IPValidationHelper.extract_ip_from_display_text(text)
        
        # 验证IP格式
        if IPValidationHelper.is_valid_ip(extracted_ip):
            return {'valid': True, 'ip': extracted_ip}
        else:
            return {'valid': False, 'error': '无效的IP地址格式'}
                
    def validate_network_input(self, text):
        """实时校验网段输入"""
        # 检查是否包含中文字符
        if IPValidationHelper.contains_chinese(text):
            cleaned_text = IPValidationHelper.clean_chinese_chars(text)
            line_edit = self.network_combo.lineEdit()
            if line_edit:
                # 阻止信号递归
                line_edit.blockSignals(True)
                line_edit.setText(cleaned_text)
                line_edit.blockSignals(False)
                return
                
        # 验证网段格式
        if text and not self._is_valid_network_format(text):
            # 如果格式不正确，可以在这里添加视觉提示
            logger.debug(f"网段格式不正确: {text}")
            
    def _is_valid_network_format(self, network_text):
        """验证网段格式是否正确"""
        if not network_text:
            return True  # 空文本允许
            
        # 检查是否为占位符文本
        invalid_texts = self.get_invalid_network_texts()
        if network_text in invalid_texts:
            return True
            
        try:
            import re
            
            # 支持的格式：
            # 1. 三段式：192.168.1
            # 2. CIDR格式：192.168.1.0/24
            
            # CIDR格式验证
            if '/' in network_text:
                import ipaddress
                try:
                    ipaddress.IPv4Network(network_text, strict=False)
                    return True
                except (ValueError, ipaddress.AddressValueError):
                    return False
            
            # 三段式格式验证
            if re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}$', network_text):
                parts = network_text.split('.')
                if len(parts) == 3:
                    for part in parts:
                        if not part.isdigit() or not 0 <= int(part) <= 255:
                            return False
                    return True
            
            # 部分输入验证（正在输入过程中）
            if re.match(r'^\d{0,3}(\.\d{0,3}){0,2}(\.\d{0,3})?$', network_text):
                parts = network_text.split('.')
                for part in parts:
                    if part and (not part.isdigit() or int(part) > 255):
                        return False
                return True
                
            return False
            
        except Exception as e:
            logger.error(f"网段格式验证异常: {e}")
            return False
            
    def get_local_networks(self):
        """获取本机网段"""
        try:
            import socket
            import ipaddress
            
            networks = []
            hostname = socket.gethostname()
            
            # 获取所有网络接口的IP地址
            try:
                # 尝试获取主要IP地址
                local_ip = socket.gethostbyname(hostname)
                if local_ip and local_ip != '127.0.0.1':
                    # 计算网段
                    ip_parts = local_ip.split('.')
                    network = f"{ip_parts[0]}.{ip_parts[1]}.{ip_parts[2]}.0/24"
                    networks.append(network)
            except:
                pass
            
            # 添加常见的私有网段
            common_networks = [
                "192.168.1.0/24",
                "192.168.0.0/24", 
                "10.0.0.0/24",
                "172.16.0.0/24"
            ]
            
            for net in common_networks:
                if net not in networks:
                    networks.append(net)
            
            if networks:
                logger.info(f"检测到本机网段: {networks}")
                self.local_networks_updated.emit(networks)
                
                return {
                    'success': True,
                    'networks': networks,
                    'primary': networks[0] if networks else None
                }
            else:
                logger.warning("未检测到本机网段")
                return {
                    'success': False,
                    'error': self.language_manager.get_text("no_network_detected", "未检测到网段")
                }
                
        except Exception as e:
            logger.error(f"获取本机网段失败: {e}")
            return {
                'success': False,
                'error': self.language_manager.get_text("network_detection_failed", "获取网段失败")
            }
            
    def on_get_local_network_clicked(self):
        """获取本机网段按钮点击处理"""
        self.get_local_networks()
            
    def on_scan_clicked(self):
        """扫描按钮点击处理"""
        if not self.network_combo:
            return
            
        network_range = self.network_combo.currentText().strip()
        
        # 检查网段是否有效
        invalid_texts = [
            self.language_manager.get_text("network_combo_placeholder", "请输入网段（如：192.168.1）"),
            self.language_manager.get_text("no_network_detected", "未检测到网段"),
            self.language_manager.get_text("network_detection_failed", "获取网段失败")
        ]
        if not network_range or network_range in invalid_texts:
            QMessageBox.warning(self.parent_widget, "警告", "请输入网段")
            return
            
        # 验证网段格式
        if not IPValidationHelper.is_valid_network(network_range):
            warning_title = self.language_manager.get_text("warning_title", "警告")
            warning_msg = self.language_manager.get_text("invalid_network_warning", "请输入正确的网段格式（例如：192.168.1 或 192.168.1.0/24）")
            QMessageBox.warning(self.parent_widget, warning_title, warning_msg)
            return
        
        # 启动或停止扫描
        if self.is_scanning():
            self.stop_scan()
        else:
            self.start_scan(network_range)
            
    def start_scan(self, network_range=None):
        """启动网络扫描
        
        参数:
            network_range: 网段范围，支持 "192.168.1" 或 "192.168.1.0/24" 格式，如果为None则使用自动检测的网段
        """
        if self._scan_state_manager.is_scanning:
            logger.warning("扫描已在进行中")
            return False
        
        try:
            # 处理网段格式
            processed_network_range = self._process_network_range(network_range)
            if network_range and not processed_network_range:
                logger.error(f"网段格式不正确: {network_range}")
                return False
            
            # 从配置获取SSH参数
            ssh_port = config.get_param('port', 22)
            ssh_username = config.get_param('username', 'muyi')
            ssh_password = config.get_param('password', 'muyi@123')
            
            # 创建并启动网络扫描线程
            self.network_scanner = NetworkScanner(self)
            self.network_scanner.device_found.connect(self._on_device_found)
            self.network_scanner.scan_finished.connect(self._on_scan_finished)
            self.network_scanner.start_scan(processed_network_range, ssh_username, ssh_password)
            
            self._scan_state_manager.start_scan()
            
            logger.info(f"开始网络扫描: {processed_network_range or '自动检测网段'}，SSH配置: {ssh_username}@端口{ssh_port}")
            return True
            
        except Exception as e:
            logger.error(f"启动网络扫描失败: {e}")
            return False
    
    def is_scanning(self):
        """检查是否正在扫描
        
        返回:
            bool: 是否正在扫描
        """
        return self._scan_state_manager.is_scanning
    
    def stop_scan(self):
        """停止网络扫描"""
        if not self._scan_state_manager.is_scanning:
            return
            
        try:
            if self.network_scanner:
                self.network_scanner.stop_scan()
            self._scan_state_manager.stop_scan()
            logger.info("停止网络扫描")
            
        except Exception as e:
            logger.error(f"停止网络扫描失败: {e}")
            
    def _process_network_range(self, network_range):
        """处理网段格式，统一转换为扫描函数可接受的格式
        
        参数:
            network_range: 网段字符串，支持 "192.168.1" 或 "192.168.1.0/24" 格式
            
        返回:
            str: 处理后的网段格式，失败返回None
        """
        if not network_range:
            return None
            
        try:
            import ipaddress
            
            # 如果包含 CIDR 格式（如 10.10.17.0/24）
            if '/' in network_range:
                # 验证CIDR格式是否有效
                ipaddress.IPv4Network(network_range, strict=False)
                return network_range  # 直接返回CIDR格式
            
            # 如果是简单格式（如 192.168.1）
            parts = network_range.split('.')
            if len(parts) == 3:
                for part in parts:
                    num = int(part)
                    if num < 0 or num > 255:
                        return None
                return network_range  # 返回三段式格式
            
            return None
            
        except (ValueError, AttributeError, ipaddress.AddressValueError):
            return None
            
    def _on_local_networks_updated(self, networks):
        """本地网段更新处理"""
        if not self.network_combo:
            return
            
        self.network_combo.clear()
        if networks:
            for network in networks:
                self.network_combo.addItem(network)
            if networks:
                self.network_combo.setCurrentIndex(0)
        else:
            no_network_text = self.language_manager.get_text("no_network_detected", "未检测到网段")
            self.network_combo.addItem(no_network_text)
    
    def _on_scan_status_changed(self, is_scanning):
        """扫描状态变化处理"""
        if not self.scan_button or not self.ip_combo:
            return
            
        if is_scanning:
            self.scan_button.start_scan()
            self.ip_combo.clear()
            scanning_text = self.language_manager.get_text("scanning_text", "正在扫描...")
            self.ip_combo.addItem(scanning_text)
        else:
            self.scan_button.stop_scan()
        
    def _on_device_found(self, ip, device_name):
        """发现设备处理"""
        if not self.ip_combo:
            return
            
        # 清除"正在扫描..."项
        scanning_text = self.language_manager.get_text("scanning_text", "正在扫描...")
        if self.ip_combo.count() == 1 and self.ip_combo.itemText(0) == scanning_text:
            self.ip_combo.clear()
            
        # 添加发现的设备
        display_text = f"{ip} ({device_name})"
        self.ip_combo.addItem(display_text)
        logger.debug(f"添加设备到列表: {display_text}")
        
        # 转发信号给外部
        self.device_found.emit(ip, device_name)
        
    def _on_scan_finished(self):
        """扫描完成处理"""
        if not self.scan_button or not self.ip_combo:
            return
            
        self.scan_button.stop_scan()
        
        # 重置扫描状态管理器的状态
        self._scan_state_manager.stop_scan()
        
        if self.ip_combo.count() == 0:
            no_devices_text = self.language_manager.get_text("no_devices_found", "未发现设备")
            self.ip_combo.addItem(no_devices_text)
        
        logger.info("网络扫描完成")
        
        # 转发信号给外部
        self.scan_finished.emit()
        
    def update_combo_placeholders(self):
        """更新下拉框占位符文本"""
        if not self.network_combo or not self.ip_combo:
            return
            
        # 更新网段下拉框占位符
        if self.network_combo.count() == 0 or self.network_combo.currentText() in [
            "请输入网段（如：192.168.1）", "Please enter network segment (e.g., 192.168.1)",
            "未检测到网段", "No network detected", "获取网段失败", "Failed to get network"
        ]:
            placeholder = self.language_manager.get_text("network_combo_placeholder")
            if placeholder:
                self.network_combo.clear()
                self.network_combo.addItem(placeholder)
        
        # 更新IP下拉框占位符
        if self.ip_combo.count() == 0 or self.ip_combo.currentText() in [
            "请选择或输入IP地址", "Please select or enter IP address",
            "正在扫描...", "Scanning...", "未发现设备", "No devices found"
        ]:
            placeholder = self.language_manager.get_text("ip_combo_placeholder")
            if placeholder:
                self.ip_combo.clear()
                self.ip_combo.addItem(placeholder)
                
    def get_selected_ip(self):
        """获取选中的IP地址"""
        if not self.ip_combo:
            return None
            
        ip_text = self.ip_combo.currentText().strip()
        
        # 检查IP是否为空或为提示文本
        invalid_ip_texts = [
            self.language_manager.get_text("ip_combo_placeholder", "请选择或输入IP地址"),
            self.language_manager.get_text("scanning_text", "正在扫描..."),
            self.language_manager.get_text("no_devices_found", "未发现设备")
        ]
        if not ip_text or ip_text in invalid_ip_texts:
            return None
            
        # 验证和提取IP
        validation_result = self.validate_ip_input(ip_text)
        if not validation_result.get('valid', True):
            ip_text = validation_result.get('cleaned_text', ip_text)
        
        # 从显示文本中提取IP地址
        if '(' in ip_text and ')' in ip_text:
            ip_text = ip_text.split('(')[0].strip()
        
        # 最终验证IP地址格式
        import re
        ip_pattern = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
        if not re.match(ip_pattern, ip_text):
            return None
            
        return ip_text
        
    def get_invalid_ip_texts(self):
        """获取无效IP文本列表"""
        return [
            self.language_manager.get_text("ip_combo_placeholder", "请选择或输入IP地址"),
            self.language_manager.get_text("scanning_text", "正在扫描..."),
            self.language_manager.get_text("no_devices_found", "未发现设备")
        ]
    
    def get_invalid_network_texts(self):
        """获取无效网段文本列表"""
        return [
            self.language_manager.get_text("network_combo_placeholder", "请输入网段（如：192.168.1）"),
            self.language_manager.get_text("no_network_detected", "未检测到网段"),
            self.language_manager.get_text("network_detection_failed", "获取网段失败")
        ]


# 为了保持向后兼容性，提供别名
NetworkScanHandler = NetworkScanManager